/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include "local-include/reg.h"
#include <cpu/cpu.h>
#include <cpu/ifetch.h>
#include <cpu/decode.h>
#include <ftrace.h>
#include "CSRs.h"

#define R(i) gpr(i)
#define Mr vaddr_read
#define Mw vaddr_write

word_t isa_raise_intr(word_t NO, vaddr_t epc);
enum {
  TYPE_I, TYPE_U, TYPE_S,
  TYPE_N, // none
	TYPE_J,
	TYPE_R,
	TYPE_B,
};

#define src1R() do { *src1 = R(rs1); } while (0)
#define src2R() do { *src2 = R(rs2); } while (0)
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
#define immS() do { *imm = (SEXT(BITS(i, 31, 25), 7) << 5) | BITS(i, 11, 7); } while(0)
#define immJ() do { *imm = SEXT((BITS(i,31,31)<<19| BITS(i,19,12)<<11|BITS(i,20,20)<<10|BITS(i,30,21)),20);}while(0)
#define immB() do { *imm = SEXT((BITS(i,31,31)<<11| BITS(i,7,7)<<10| BITS(i,30,25)<<4|BITS(i,11,8)),12);}while(0)
static void decode_operand(Decode *s, int *dest, word_t *src1, word_t *src2, word_t *imm, int type) {
  uint32_t i = s->isa.inst.val;
  int rd  = BITS(i, 11, 7);
  int rs1 = BITS(i, 19, 15);
  int rs2 = BITS(i, 24, 20);
  *dest = rd;
  switch (type) {
    case TYPE_I: src1R();          immI(); break;
    case TYPE_U:                   immU(); break;
    case TYPE_S: src1R(); src2R(); immS(); break;
		case TYPE_J: 									 immJ(); break;
		case TYPE_R: src1R(); src2R();				 break;
		case TYPE_B: src1R(); src2R(); immB(); break;
  }
}
word_t srai(word_t src1, word_t num){
	for(int i = 0; i<num;i++){
					src1 = BITS(src1,63,63)<<63|(src1 >> 1);
	}
	return src1;
}

static int decode_exec(Decode *s) {
  int dest = 0;
  word_t src1 = 0, src2 = 0, imm = 0;
  s->dnpc = s->snpc;

#define INSTPAT_INST(s) ((s)->isa.inst.val)
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
  decode_operand(s, &dest, &src1, &src2, &imm, concat(TYPE_, type)); \
  __VA_ARGS__ ; \
}

  INSTPAT_START();
//简述INSTPAT的功能，先对第一个参数的模式进行解析生成掩模板，然后根据真实的指令值与模板进行对比，不成功进行下一条INSTPAT
//成功则更具类型进行取操作数，并执行计算
  INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq    , B, if(src1 == src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne    , B, if(src1 != src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge    , B, if((long)src1 >= (long)src2) s->dnpc = s->pc + imm*2);
	//new
  INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu    , B, if(src1 >= src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt    , B, if((long)src1 < (long)src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu    , B, if(src1 < src2) s->dnpc = s->pc + imm*2);

  INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc  , U, R(dest) = s->pc + imm);
  INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui  ,  U, R(dest) = imm);

  INSTPAT("??????? ????? ????? 011 ????? 00000 11", ld     , I, R(dest) = Mr(src1 + imm, 8));
  INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw     , I, R(dest) = SEXT(Mr(src1 + imm, 4),32));
  INSTPAT("??????? ????? ????? 110 ????? 00000 11", lwu     , I, R(dest) = Mr(src1 + imm, 4));
  INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh   ,  I, R(dest) = SEXT(Mr(src1 + imm, 2),16));
  INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu   ,  I, R(dest) = Mr(src1 + imm, 2));
  INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb    ,  I, R(dest) = SEXT(Mr(src1 + imm, 1),8));
  INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu   ,  I, R(dest) = Mr(src1 + imm, 1));
  INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi   , I, R(dest) = src1 + imm);
	//new
  INSTPAT("??????? ????? ????? 011 ????? 00100 11", SLTIU  , I, R(dest) = src1<imm?1:0);
	//new 12.25
  INSTPAT("??????? ????? ????? 010 ????? 00100 11", SLTI  , I, R(dest) = SEXT(src1,64)<SEXT(imm,64)?1:0);
  INSTPAT("??????? ????? ????? 000 ????? 00110 11", addiw  , I, R(dest) =SEXT(BITS(src1 + imm,31,0),32));
  INSTPAT("010000? ????? ????? 101 ????? 00100 11", srai  ,  I, R(dest) = srai(src1,BITS(imm,5,0)));
	//new
  INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi  ,  I, R(dest) = src1 & imm);
	//new
  INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori  ,  I, R(dest) = src1 | imm);
  INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori  ,  I, R(dest) = src1 ^ imm);
  INSTPAT("000000? ????? ????? 001 ????? 00100 11", slli  ,  I, R(dest) = src1 << BITS(imm,5,0));
  INSTPAT("000000? ????? ????? 101 ????? 00100 11", srli  ,  I, R(dest) = src1 >> BITS(imm,5,0));
  INSTPAT("0000000 ????? ????? 001 ????? 00110 11", slliw  ,  I, R(dest) = SEXT(BITS(BITS(src1,31,0) << BITS(imm,4,0),31,0),32));
  INSTPAT("0100000 ????? ????? 101 ????? 00110 11", sraiw  ,  I, R(dest) = srai(SEXT(BITS(src1,31,0),32),BITS(imm,4,0)));
  INSTPAT("0000000 ????? ????? 101 ????? 00110 11", srliw  ,  I, R(dest) = SEXT(BITS(BITS(src1,31,0) >> BITS(imm,4,0),31,0),32));

  INSTPAT("0000000 ????? ????? 000 ????? 01110 11", addw   , R, R(dest) =SEXT(BITS(BITS(src1,31,0)+BITS(src2,31,0),31,0),32));
  INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub    , R, R(dest) =src1 - src2);
  INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add   ,  R, R(dest) =src1 + src2);
	//new
  INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll   ,  R, R(dest) =src1 << (BITS(src2,5,0)));
  INSTPAT("0000000 ????? ????? 001 ????? 01110 11", sllw  ,  R, R(dest) =SEXT(BITS(BITS(src1,31,0)<< BITS(src2,4,0),31,0),32));
  INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and   ,  R, R(dest) = src1 &src2);
  INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu  ,  R, R(dest) = src1 <src2 ? 1:0);
  INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or    ,  R, R(dest) = src1 |src2);
	//new
  INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor   ,  R, R(dest) = src1 ^src2);
  INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt  ,  R, R(dest) =(long)src1 <(long)src2 ? 1:0);
  INSTPAT("0000001 ????? ????? 000 ????? 01110 11", mulw   ,  R, R(dest) = SEXT(BITS(BITS(src1,31,0)*BITS(src2,31,0),31,0),32));
  INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul   ,  R, R(dest) = src1*src2);
	//new
  INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu   ,  R, R(dest) = src1%src2);
	//new
  INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem   ,  R, R(dest) = (long)src1%(long)src2);
	//new
  INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl  ,  R, R(dest) =src1 >> BITS(src2,5,0));
  //new
	INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu   ,  R, R(dest) = (unsigned long)src1/(unsigned long)src2);
	//new
	INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div   ,  R, R(dest) = (long)src1/(long)src2);
  INSTPAT("0000000 ????? ????? 101 ????? 01110 11", srlw  ,  R, R(dest) =SEXT(BITS(src1,31,0) >> BITS(src2,4,0),32));
  INSTPAT("0100000 ????? ????? 101 ????? 01110 11", sraw  ,  R, R(dest) =srai(SEXT(BITS(src1,31,0),32),BITS(src2,4,0)));
  INSTPAT("0000001 ????? ????? 100 ????? 01110 11", divw   ,  R, R(dest) = SEXT(BITS((int)BITS(src1,31,0)/(int)BITS(src2,31,0),31,0),32));
  INSTPAT("0000001 ????? ????? 110 ????? 01110 11", remw   ,  R, R(dest) = SEXT(BITS((int)BITS(src1,31,0)%(int)BITS(src2,31,0),31,0),32));
	//new
  INSTPAT("0000001 ????? ????? 111 ????? 01110 11", remuw   ,  R, R(dest) = SEXT(BITS(BITS(src1,31,0)%BITS(src2,31,0),31,0),32));
	//new
  INSTPAT("0000001 ????? ????? 101 ????? 01110 11", divuw   ,  R, R(dest) = SEXT(BITS(BITS(src1,31,0)/BITS(src2,31,0),31,0),32));
  INSTPAT("0100000 ????? ????? 000 ????? 01110 11", subw  ,  R, R(dest) =SEXT(BITS(BITS(src1,31,0)-BITS(src2,31,0),31,0),32));

  INSTPAT("??????? ????? ????? 011 ????? 01000 11", sd     , S, Mw(src1 + imm, 8, src2));
  INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh    ,  S, Mw(src1 + imm, 2, src2));
  INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb    ,  S, Mw(src1 + imm, 1, src2));
  INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw     , S, Mw(src1 + imm, 4, src2));


#ifdef CONFIG_FTRACE
  INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal    , J, R(dest) = s->pc + 4; s->dnpc = s->pc + imm*2;ftrace_jal(s->pc,dest,s->dnpc));
  INSTPAT("??????? ????? ????? 000 ????? 11001 11", jalr   , I, R(dest) = s->pc + 4; s->dnpc = ((src1 + imm) >> 1) <<1;ftrace_jalr(s->pc,dest,(int)BITS(s->isa.inst.val,19,15),imm,s->dnpc));
#else
  INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal    , J, R(dest) = s->pc + 4; s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 000 ????? 11001 11", jalr   , I, R(dest) = s->pc + 4; s->dnpc = ((src1 + imm) >> 1) <<1);
#endif
  INSTPAT("??????? ????? ????? 001 ????? 00011 11", fencei , I, );
//Zicsr
  INSTPAT("??????? ????? ????? 001 ????? 11100 11", CSRRW  , I, R(dest) =read_csr(BITS(imm,11,0));write_csr(BITS(imm,11,0),src1));
  INSTPAT("??????? ????? ????? 010 ????? 11100 11", CSRRS  , I, R(dest) =read_csr(BITS(imm,11,0));write_csr(BITS(imm,11,0),src1|read_csr(BITS(imm,11,0))));
//privileged
  INSTPAT("0011000 00010 00000 000 00000 11100 11", MRET  , I, s->dnpc =read_csr(0x341));
	
  INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0
  INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall , N,s->dnpc = isa_raise_intr(11,s->pc));
  INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv    , N, INV(s->pc));
  INSTPAT_END();

  R(0) = 0; // reset $zero to 0
  return 0;
}

int isa_exec_once(Decode *s) {
  // pc + 4 is in inst_fetch function
  s->isa.inst.val = inst_fetch(&s->snpc, 4);
  return decode_exec(s);
}

static int decode_get_npc(Decode *s) {
  int dest = 0;
  word_t src1 = 0, src2 = 0, imm = 0;
  s->dnpc = s->snpc;
#define INSTPAT_INST(s) ((s)->isa.inst.val)
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
  decode_operand(s, &dest, &src1, &src2, &imm, concat(TYPE_, type)); \
  __VA_ARGS__ ; \
}
  INSTPAT_START();
  INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq    , B, if(src1 == src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne    , B, if(src1 != src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge    , B, if((long)src1 >= (long)src2) s->dnpc = s->pc + imm*2);
	//new
  INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu    , B, if(src1 >= src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt    , B, if((long)src1 < (long)src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu    , B, if(src1 < src2) s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal    , J, s->dnpc = s->pc + imm*2);
  INSTPAT("??????? ????? ????? 000 ????? 11001 11", jalr   , I, s->dnpc = ((src1 + imm) >> 1) <<1);
//privileged
  INSTPAT("0011000 00010 00000 000 00000 11100 11", MRET  , I,s->dnpc =read_csr(0x341));
  INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall , N,s->dnpc = read_csr(0x305));
	//s->dnpc = s->snpc + 4;
	//return 0;
  //INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv    , N, INV(s->pc));
  INSTPAT_END();

  R(0) = 0; // reset $zero to 0
  return 0;
}
uint64_t difftest_get_npc(uint64_t pc){
  Decode s;
  s.pc = pc;
  s.snpc = pc;
  s.isa.inst.val = inst_fetch(&(s.snpc), 4);
	decode_get_npc(&s);
	return s.dnpc;
}
